<template>
  <div class="p-6 max-w-7xl mx-auto">
    <h1 class="text-3xl font-bold mb-6 text-blue-800">检察院 RAG 后端调试平台</h1>
    
    <el-alert
      v-if="globalMessage"
      :title="globalMessage.title"
      :type="globalMessage.type"
      show-icon
      closable
      class="mb-6"
      @close="globalMessage = null"
    />

    <el-tabs type="border-card">
      
      <el-tab-pane label="RAG 提问查询">
          
        <div class="grid grid-cols-1 md:grid-cols-2 gap-8">
            
            <el-card header="文档上传与索引 (Indexing)">
                <el-upload
                  ref="uploadRef"
                  :auto-upload="false"
                  :on-change="handleFileChange"
                  :file-list="fileList"
                  :limit="1"
                  drag
                  class="mb-4"
                >
                  <el-icon class="el-icon--upload"><i-ep-upload-filled /></el-icon>
                  <div class="el-upload__text">
                    拖拽文件到此处 或 <em>点击选择</em>
                  </div>
                  <template #tip>
                    <div class="el-upload__tip">仅支持 PDF 文档上传并触发自动索引。</div>
                  </template>
                </el-upload>
                <el-button 
                  type="success" 
                  @click="uploadDocument" 
                  :disabled="fileList.length === 0" 
                  :loading="uploadLoading"
                >
                  {{ uploadLoading ? '索引中...' : '上传并索引文档' }}
                </el-button>

                <el-divider v-if="currentTask" content-position="left">当前任务状态</el-divider>
                <el-alert 
                  v-if="currentTask"
                  :title="`任务ID: ${currentTask.task_id} | 状态: ${currentTask.status.toUpperCase()}`"
                  :type="currentTask.status === 'error' ? 'error' : (currentTask.status === 'success' ? 'success' : 'info')"
                  :description="currentTask.message"
                  show-icon
                  class="mt-3"
                />
            </el-card>

            <el-card header="RAG 提问查询">
                <el-input 
                  v-model="queryText" 
                  type="textarea" 
                  :rows="3" 
                  placeholder="请输入检察院相关的问题..." 
                  class="mb-4"
                  @keyup.enter="submitQuery"
                />
                <el-button 
                  type="primary" 
                  @click="submitQuery" 
                  :loading="queryLoading"
                  class="w-full"
                >
                  {{ queryLoading ? '查询中...' : '提交查询' }}
                </el-button>
                
                <el-divider />
                
                <h3 class="font-semibold mb-2">RAG 回答:</h3>
                <el-skeleton v-if="queryLoading" animated />
                <el-alert v-else-if="queryError" :title="queryError" type="error" />
                <div v-else-if="queryResult.answer" class="bg-gray-50 p-3 rounded border">
                  <p class="whitespace-pre-wrap text-sm">{{ queryResult.answer }}</p>
                  <div v-if="queryResult.sources.length" class="mt-3 pt-2 border-t text-xs text-gray-600">
                    **检索源文件:** <el-tag v-for="source in queryResult.sources" :key="source" size="small" class="mr-2 mb-1">
                      {{ source }}
                    </el-tag>
                  </div>
                </div>
                <p v-else class="text-gray-400 text-sm">暂无查询结果。</p>
            </el-card>
        </div>
          
      </el-tab-pane>

      <el-tab-pane label="RAG 系统配置">
        
        <el-card class="mb-4" header="RAG 核心配置">
          
          <el-tabs type="card" class="config-tabs">
            
            <el-tab-pane label="召回与重排">
              <el-form label-width="200px" class="mt-4" :model="ragConfig">
                <el-form-item label="最终 Top K (retrieval_top_k)">
                    <el-input-number v-model="ragConfig.retrieval_top_k" :min="1" :max="20" controls-position="right" />
                    <span class="ml-3 text-gray-500 text-sm">送入 LLM 的文档块数量。</span>
                </el-form-item>
                
                <el-form-item label="重排前初始 K 乘数">
                    <el-input-number v-model="ragConfig.initial_retrieval_multiplier" :min="1" :max="10" controls-position="right" />
                    <span class="ml-3 text-gray-500 text-sm">初始召回 K = Top K * 乘数。</span>
                </el-form-item>
                
                <el-form-item label="使用重排器 (use_reranker)">
                    <el-switch v-model="ragConfig.use_reranker" />
                </el-form-item>
                <el-form-item label="重排器类型">
                    <el-radio-group v-model="ragConfig.reranker_type">
                      <el-radio label="llm">LLM (基于 LLM 评分)</el-radio>
                      <el-radio label="local">Local (基于本地模型)</el-radio>
                    </el-radio-group>
                </el-form-item>
                <el-form-item label="历史召回 K">
                    <el-input-number v-model="ragConfig.history_retrieval_top_k" :min="1" controls-position="right" />
                </el-form-item>
                <el-form-item label="引用相似度阈值">
                    <el-input-number v-model="ragConfig.citation_similarity_threshold" :min="0.0" :max="1.0" :step="0.05" controls-position="right" />
                    <span class="ml-3 text-gray-500 text-sm">低于此值，句子不会被引用。</span>
                </el-form-item>

              </el-form>
            </el-tab-pane>

            <el-tab-pane label="文本分割与切分">
                <el-form label-width="200px" class="mt-4" :model="ragConfig">
                    <el-form-item label="切分方法 (chunk_method)">
                      <el-radio-group v-model="ragConfig.chunk_method">
                        <el-radio label="fixed_size">固定大小</el-radio>
                        <el-radio label="semantic">语义切分</el-radio>
                      </el-radio-group>
                    </el-form-item>
                    
                    <el-form-item v-if="ragConfig.chunk_method === 'fixed_size'" label="块大小 (chunk_size)">
                      <el-input-number v-model="ragConfig.chunk_size" :min="128" :step="64" controls-position="right" />
                    </el-form-item>
                    
                    <el-form-item v-if="ragConfig.chunk_method === 'fixed_size'" label="块重叠 (chunk_overlap)">
                      <el-input-number v-model="ragConfig.chunk_overlap" :min="0" controls-position="right" />
                    </el-form-item>

                    <el-form-item v-if="ragConfig.chunk_method === 'semantic'" label="语义缓冲区大小">
                      <el-input-number v-model="ragConfig.semantic_buffer_size" :min="1" controls-position="right" />
                    </el-form-item>
                    
                    <el-form-item v-if="ragConfig.chunk_method === 'semantic'" label="语义百分比阈值">
                      <el-input-number v-model="ragConfig.semantic_threshold" :min="0" :max="100" controls-position="right" />
                      <span class="ml-3 text-gray-500 text-sm">0-100%，越低切分越细。</span>
                    </el-form-item>
                </el-form>
            </el-tab-pane>

            <el-tab-pane label="LLM 与系统参数">
                <el-form label-width="200px" class="mt-4" :model="ragConfig">
                    <el-form-item label="LLM 最大上下文 Tokens">
                      <el-input-number v-model="ragConfig.llm_max_context_tokens" :min="1024" :step="1024" controls-position="right" />
                    </el-form-item>
                    
                    <el-form-item label="LLM 最大重试次数">
                      <el-input-number v-model="ragConfig.llm_max_retries" :min="0" controls-position="right" />
                    </el-form-item>
                    
                    <el-form-item label="重试基础延迟 (秒)">
                      <el-input-number v-model="ragConfig.retry_base_delay" :min="0.1" :step="0.5" controls-position="right" />
                    </el-form-item>
                </el-form>
            </el-tab-pane>

            <el-tab-pane label="提示词模板">
                <el-form label-position="top" :model="ragConfig">
                    <el-form-item label="主问答提示词 (qa_prompt_template)">
                      <el-input v-model="ragConfig.qa_prompt_template" type="textarea" :rows="8" placeholder="包含 {chat_history_context}, {context_str}, {query_str} 占位符" />
                    </el-form-item>
                    
                    <el-form-item label="标题生成提示词 (title_prompt_template)">
                      <el-input v-model="ragConfig.title_prompt_template" type="textarea" :rows="4" placeholder="包含 {query_str}, {context_str} 占位符" />
                    </el-form-item>

                    <el-form-item label="通用聊天提示词 (general_chat_prompt_template)">
                      <el-input v-model="ragConfig.general_chat_prompt_template" type="textarea" :rows="4" placeholder="包含 {chat_history_context}, {query_str} 占位符" />
                    </el-form-item>
                </el-form>
            </el-tab-pane>
          </el-tabs>
          <el-divider />

          <div class="flex justify-between items-center mt-4">
            <div>
              <el-button type="primary" @click="updateConfig" :loading="configLoading" size="large">
                {{ configLoading ? '保存中' : '保存所有 RAG 配置' }}
              </el-button>
            </div>
            
            <el-popconfirm
              title="确认清理整个 ChromaDB 集合？所有文档索引将被删除！"
              confirm-button-text="确认清理"
              cancel-button-text="取消"
              @confirm="clearCollection"
            >
              <template #reference>
                <el-button type="danger" plain :loading="clearLoading">
                  {{ clearLoading ? '清理中...' : '清理知识库' }}
                </el-button>
              </template>
            </el-popconfirm>
          </div>

        </el-card>
        
      </el-tab-pane>

      <el-tab-pane label="RAG 深度调试与数据管理">
        <DebugPanel /> 
      </el-tab-pane>

    </el-tabs>
  </div>
</template>

<script setup lang="ts">
import { ref, reactive, onMounted } from 'vue';

import { 
    getRagConfig, 
    updateRagConfig, 
    clearChromaDB as apiClearChromaDB, 
} from '~/api/ragApi';
import type { RagConfig as FullRagConfig } from '~/api/ragApi';

import { 
    ragQueryWithContextStream, 
    type ChatQueryRequestPayload, 
    type StreamChunkData
} from '~/api/queryApi'; 

import { 
    uploadSingleFile, 
    getTaskStatus, 
    type UploadResponse, 
    type TaskStatus 
} from '~/api/uploadApi'; 

import ChatHistoryManager from '~/comp/ChatHistoryManager.vue';
import DebugPanel from '~/comp/DebugPanel.vue';
import type { ElUpload, UploadFile, UploadRawFile } from 'element-plus';
interface GlobalAlertMessage {
  title: string;
  type: 'success' | 'error' | 'warning' | 'info';
}
const globalMessage = ref<GlobalAlertMessage | null>(null); 

const setGlobalMessage = (title: string, type: GlobalAlertMessage['type'] = 'success') => {
  globalMessage.value = { title, type };
  setTimeout(() => { globalMessage.value = null; }, 5000);
};

// --- RAG 配置状态 ---
const ragConfig = reactive({
  // 召回与重排
  retrieval_top_k: 5,
  initial_retrieval_multiplier: 3,
  history_retrieval_top_k: 5,
  use_reranker: true,
  reranker_type: 'llm', // 方便演示
  
  // 文本分割
  chunk_method: 'semantic',
  chunk_size: 512,
  chunk_overlap: 50,
  
  // 语义切分
  semantic_buffer_size: 1,
  semantic_threshold: 95,
  
  // 引用阈值 (对应你原先的 threshold)
  citation_similarity_threshold: 0.3,
  
  // LLM 参数
  llm_max_context_tokens: 4096,
  llm_max_retries: 3,
  retry_base_delay: 1.0,

  // 提示词模板 (不在这里初始化，太长)
  qa_prompt_template: '',
  // ... 必须包含所有字段，否则更新时会丢失，但为简洁这里省略，
  // 实际应该从 getRagConfig 中完整赋值。
}) as FullRagConfig; 
const configLoading = ref(false);

// --- 文档上传状态 ---
const uploadRef = ref<InstanceType<typeof ElUpload> | null>(null);
const fileList = ref<UploadFile[]>([]);
const uploadLoading = ref(false);

// --- 查询状态 ---
const queryText = ref('');
const queryResult = reactive({
  answer: '',
  sources: [] as string[],
});
const queryLoading = ref(false);
const queryError = ref<string | null>(null);

// --- 系统维护状态 ---
const clearLoading = ref(false);

const currentTask = ref<TaskStatus | null>(null); // 用于跟踪任务状态
let taskPollingTimer: NodeJS.Timeout | null = null;
// 1. RAG 配置调整 (使用封装的 API)
const updateConfig = async () => {
  configLoading.value = true;
  try {
    // 关键：直接发送整个 reactive 对象，包含了所有 snake_case 键名
    const updated = await updateRagConfig(ragConfig);

    // 重新赋值以获取后端可能进行的修正
    Object.assign(ragConfig, updated);
    
    setGlobalMessage('RAG 参数配置更新成功。', 'success');
  } catch (error) {
    let errorMessage = '未知错误';
    if (error instanceof Error) {
      errorMessage = error.message;
    }
    setGlobalMessage(`配置更新异常: ${errorMessage}`, 'error');
  } finally {
    configLoading.value = false;
  }
};

// 2. 清理 ChromaDB Collection (使用封装的 API)
const clearCollection = async () => {
  clearLoading.value = true;
  try {
    await apiClearChromaDB();
    setGlobalMessage('ChromaDB Collection 清理成功，所有索引文档已删除。', 'warning');
  } catch (error) {
    let errorMessage = '未知错误';
    if (error instanceof Error) {
      errorMessage = error.message;
    }
    setGlobalMessage(`清理数据库异常: ${errorMessage}`, 'error');
  } finally {
    clearLoading.value = false;
  }
};


// 3. 文档上传与索引 (使用封装的 API)
const handleFileChange = (file: UploadFile) => {
  fileList.value = [file];
};

const uploadDocument = async () => {
  if (fileList.value.length === 0) return;

  uploadLoading.value = true;
  // 确保 file 存在且是 UploadRawFile 类型
  const file = fileList.value[0]!.raw as File; 

  // 1. 清理旧任务
  if (taskPollingTimer) { clearInterval(taskPollingTimer); }
  currentTask.value = null;

  try {
    // 调用封装的 uploadSingleFile，它返回 Task ID
    const uploadRes: UploadResponse = await uploadSingleFile(file);

    if (uploadRes.status === 'duplicate') {
      setGlobalMessage(`文件内容已存在，未重复上传。`, 'warning');
    } else if (uploadRes.status === 'scheduled' && uploadRes.task_id) {
      setGlobalMessage(`文件 ${file.name} 已上传。索引任务 [${uploadRes.task_id}] 已调度。`, 'info');
      
      fileList.value = []; // 清空文件列表
      if (uploadRef.value) { uploadRef.value.clearFiles(); }

      // 2. 启动任务轮询
      startTaskPolling(uploadRes.task_id);

    } else {
      throw new Error(uploadRes.message || '文件上传失败。');
    }

  } catch (error) {
    let errorMessage = '未知错误';
    if (error instanceof Error) { errorMessage = error.message; }
    setGlobalMessage(`文件索引失败: ${errorMessage}`, 'error');
  } finally {
    uploadLoading.value = false;
  }
};

// 任务轮询逻辑
const startTaskPolling = (taskId: string) => {
    const poll = async () => {
        try {
            const status = await getTaskStatus(taskId);
            currentTask.value = status;

            if (status.status === 'success' || status.status === 'error') {
                clearInterval(taskPollingTimer!);
                taskPollingTimer = null;
                setGlobalMessage(`任务 [${taskId}] 已完成: ${status.status.toUpperCase()}。${status.result?.message || ''}`, status.status);
            }
        } catch (e) {
            clearInterval(taskPollingTimer!);
            taskPollingTimer = null;
            currentTask.value = { 
                task_id: taskId, task_type: 'unknown', status: 'error', 
                timestamp: new Date().toISOString(), message: '无法查询任务状态', 
                result: null, initial_data: null 
            };
            setGlobalMessage(`任务 [${taskId}] 轮询失败。`, 'error');
        }
    };

    // 立即执行一次，然后每 3 秒执行一次
    poll();
    taskPollingTimer = setInterval(poll, 3000);
};

onBeforeUnmount(() => {
    if (taskPollingTimer) {
        clearInterval(taskPollingTimer);
    }
});

// 4. RAG 提问查询 (升级为流式)
const submitQuery = async () => {
  if (!queryText.value.trim()) {
    setGlobalMessage('请输入查询问题。', 'warning');
    return;
  }

  queryLoading.value = true;
  queryError.value = null;
  queryResult.answer = ''; // 清空答案
  queryResult.sources = [];

  // 1. 构造 Payload
  const payload: ChatQueryRequestPayload = {
    question: queryText.value.trim(),
    collection_name: 'public_collection', 
    account_id: 99999,
    
    // *** 关键修复：使用 snake_case 的键名和属性访问 ***
    rag_config: { 
      // 使用后端期望的 retrieval_top_k 字段名
      retrieval_top_k: ragConfig.retrieval_top_k, 
      // 使用 citation_similarity_threshold 字段名（对应原 threshold）
      citation_similarity_threshold: ragConfig.citation_similarity_threshold 
    },
    // 暂不使用 chat_history 和 target_file_ids
  };

  try {
    // 2. 调用流式 API
    await ragQueryWithContextStream(
      payload,
      // onChunkReceived: 使用 StreamChunkData 类型
      (chunkData: StreamChunkData) => { 
        // 1. 文本累积
        // 检查 content 是否存在且非空（后端在 is_last=true 时发送空 content）
        if (chunkData.content) { 
          queryResult.answer += chunkData.content; // 累积文本
        }
        
        // 2. 最终元数据处理
        // 检查是否是最后一个块，并且包含 metadata
        if (chunkData.is_last && chunkData.metadata) {
            // 后端发送的 metadata 已经是解析好的 JSON 对象
            const metadata = chunkData.metadata;

            // 提取 rag_sources
            const ragSources = metadata.rag_sources || [];
            
            // 使用 Set 来确保源文件名称和页码是唯一的
            const sourceNames = new Set<string>();
            
            ragSources.forEach((s: any) => {
                if (s.file_name) {
                    // 格式化源文件信息：文件名 (页码)
                    let sourceStr = s.file_name;
                    if (s.page_number && s.page_number !== 'N/A') {
                        sourceStr += ` (页: ${s.page_number})`;
                    }
                    sourceNames.add(sourceStr);
                }
            });

            // 更新前端展示的 sources 列表
            queryResult.sources = Array.from(sourceNames);
            
            // 可以在这里处理 sentence_citations，但目前只要求展示 sources
            
        }
      },
      // onStreamEnd
      () => {
        queryLoading.value = false;
        setGlobalMessage('流式查询完成。', 'success');
      },
      // onError
      (error) => {
        // ... (错误处理逻辑) ...
      }
    );
  } catch (error) {
    let errorMessage = '未知错误';
    if (error instanceof Error) {
      errorMessage = error.message;
    }
    // 捕获 fetch 之前的错误 (如参数检查)
    queryLoading.value = false;
    queryError.value = `请求初始化失败：${errorMessage}`;
    setGlobalMessage(`请求失败: ${errorMessage}`, 'error');
  }
};

// 页面加载时尝试获取当前配置 (使用封装的 API)
onMounted(async () => {
    try {
      const data = await getRagConfig();
      // 关键：加载所有字段
      Object.assign(ragConfig, data); 
    } catch (e) {
      console.warn('无法获取RAG配置，使用默认值。', e);
    }
});
</script>